// Copyright (c) 2025, 大连理工大学 (Dalian University of Technology)
//
// Licensed under the Mulan PSL v2.
// You can use this file according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of the License at
//
//     http://license.coscl.org.cn/MulanPSL2
//
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. SEE THE MULAN PSL v2
// FOR MORE DETAILS.

#include "DBManager/Service/Input/Constraint/RElementSummaryService.h"

#include <list>
#include <vector>

#include "Utility/Algebra/Matrix.h"

#include "DataStructure/Common/Id.h"
#include "DataStructure/Input/Element/ElementTypes.h"

#include "DBManager/Common/ServiceMacro.h"

#include "RElementSummaryService.h"

using namespace SG::DBManager;

SERVICE_REG_FOR_SUMMARY (RElementSummaryService, IRElementSummaryRepository)

namespace
{
    /**
     * @brief    在创建该Summary时，初始化所有包含的数据Service 如 CRODService、CPYRAM5Service 等
     *           绑定该Service的函数
     * @author   wuxingchuang
     * @date     2025.02.20
     */
    std::vector<RElementSummaryService::SummaryCreateService>* g_summaryCreateRElementService = nullptr;

}  // namespace

RElementSummaryService::RElementSummaryService (DBServiceFactory* const dbServiceFactory, IRElementSummaryRepository& repos)
    : InputServiceBase<IRElementSummaryRepository> (dbServiceFactory, repos)
{}

RElementSummaryService::~RElementSummaryService () = default;

std::vector<SG::DataStructure::FEM::RElementType> RElementSummaryService::GetAllRElementTypes () const
{
    return m_repository.GetAllRElementTypes ();
}

SG::DataStructure::FEM::RElementType RElementSummaryService::GetRElementType (SG::DataStructure::Common::Id eid) const
{
    return m_repository.GetRElementType (eid);
}

/// @brief 类型为`type`的单元的数量
std::size_t RElementSummaryService::GetRElementSize (const SG::DataStructure::FEM::RElementType type) const
{
    return m_repository.GetRElementSize (type);
}

std::pair<SG::DataStructure::FEM::RElementType, std::size_t>
RElementSummaryService::FindRElement (SG::DataStructure::Common::Id                            eleId,
                                      const std::vector<SG::DataStructure::FEM::RElementType>& etypes) const
{
    SG::DBManager::SummaryInfo<SG::DataStructure::FEM::RElementType> entity;
    if (SG::DataStructure::Common::Status::STATUS_Success == m_repository.FindById (eleId, entity))
    {
        return std::pair<SG::DataStructure::FEM::RElementType, std::size_t> (entity.m_type, entity.m_index);
    }

    SGError << "Cannot find the element. id:" << eleId;

    return std::pair<SG::DataStructure::FEM::RElementType, std::size_t> ();
}

std::vector<SG::DataStructure::Common::Id> RElementSummaryService::GetAllRElementId () const
{
    return m_repository.GetAllId ();
}

SG::DataStructure::Common::Status RElementSummaryService::CopyData (DBServiceFactory* const                    dest,
                                                                    std::vector<SG::DataStructure::Common::Id> ids) const
{
    std::map<std::size_t, std::list<SG::DataStructure::Common::Id>> map;
    for (auto&& id : ids)
    {
        auto        type   = GetRElementType (id);
        std::size_t typeId = typeid (decltype (type)).hash_code () + type;

        if (map.find (typeId) == map.end ())
        {
            map[typeId] = std::list<SG::DataStructure::Common::Id> ();
        }
        map[typeId].push_back (id);
    }

    auto funMap = m_dbServiceFactory->GetDatabase ()->GetHub()->CopyDataFunMap ();
    for (auto&& pair : map)
    {
        if (funMap.count (pair.first) > 0)
        {
            funMap[pair.first](m_dbServiceFactory, dest, { pair.second.begin (), pair.second.end () });
        }
    }

    return SG::DataStructure::Common::Status::STATUS_Success;
}

bool RElementSummaryService::RegisterService (SummaryCreateService&& service)
{
    if (g_summaryCreateRElementService == nullptr)
    {
        g_summaryCreateRElementService = new std::vector<SummaryCreateService> ();
    }

    g_summaryCreateRElementService->emplace_back (std::move (service));
    return true;
}

void RElementSummaryService::CreateSummary (DBServiceFactory* const dbServiceFactory)
{
    for (size_t i = 0; i < g_summaryCreateRElementService->size (); i++)
    {
        g_summaryCreateRElementService->at (i) (dbServiceFactory);
    }
}
